﻿#include "FarFieldDataGenerator.h"
#include <vtkTable.h>
#include <vtkDataSet.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkStructuredGrid.h>
#include <vtkTableToStructuredGrid.h>
#include <vtkStructuredGridWriter.h>
#include "CommonFunction.h"

namespace pst
{

    FarFieldDataGenerator::FarFieldDataGenerator(QObject* parent)
        : QObject(parent)
        , m_useLog(false)
        , m_useNormalize(false)
        , m_originalTable(nullptr)
        , m_resultTable(nullptr)
        , m_resultDataSet(vtkSmartPointer<vtkStructuredGrid>::New())
        , m_logFactory(10)
        , m_tableExtends{ 0,0,0 }
        , m_originalTableColNumber{ 0 }
        , m_originalTableRowNumber(0)
    {
    }

    FarFieldDataGenerator::~FarFieldDataGenerator()
    {
    }

    void FarFieldDataGenerator::setInputData(vtkTable* table)
    {
        m_originalTable = table;
    }

    void FarFieldDataGenerator::setLogTheData(bool useLog)
    {
        m_useLog = useLog;
    }

    bool FarFieldDataGenerator::getLogTheData()
    {
        return m_useLog;
    }

    void FarFieldDataGenerator::setNormalizeTheData(bool useNormalize)
    {
        m_useNormalize = useNormalize;
    }

    bool FarFieldDataGenerator::getNormalizeTheData()
    {
        return m_useNormalize;
    }

    void FarFieldDataGenerator::setTableExtends(int xMax, int yMax, int zmax)
    {
        m_tableExtends[0] = xMax;
        m_tableExtends[1] = yMax;
        m_tableExtends[2] = zmax;
    }

    bool FarFieldDataGenerator::update()
    {
        if (m_originalTable == nullptr)
        {
            return false;
        }
        //先归一化
        vtkSmartPointer<vtkTable> normalizedTable;
        if (m_useNormalize)
        {
            normalizedTable = vtkSmartPointer<vtkTable>::New();
            normalizeTheTable(m_originalTable, normalizedTable);
        }
        else
        {
            normalizedTable = m_originalTable;
        }

        //再取对数
        double colorOffeset{ 0 };
        if (m_useLog)
        {
            m_resultTable = vtkSmartPointer<vtkTable>::New();
            logTheTable(normalizedTable, m_resultTable, colorOffeset);
        }
        else
        {
            m_resultTable = normalizedTable;
        }
        vtkNew<vtkTable> transformedTLogTable;
        auto suc = transformRCSTableToFourColumnsRectangularTable(m_resultTable, transformedTLogTable, colorOffeset);
        if (!suc)
        {
            return false;
        }
        transformTableToStructuredGrid(transformedTLogTable, m_resultDataSet, m_tableExtends[0], m_tableExtends[1], m_tableExtends[2]);
        m_resultDataSet->GetPointData()->SetActiveAttribute(0, vtkDataSetAttributes::AttributeTypes::SCALARS);
        return true;
    }

    vtkDataSet* FarFieldDataGenerator::getOutputData()
    {
        return m_resultDataSet;
    }

    void FarFieldDataGenerator::SetLogFactory(double factory)
    {
        m_logFactory = factory;
    }

    bool FarFieldDataGenerator::ExtractPhiNum(vtkTable* table, std::vector<double>& numVec)
    {
        auto oldTableColumeNum = table->GetNumberOfColumns();
        if (oldTableColumeNum < 2)
        {
            std::cout << "The table must have 2 columns at least;" << std::endl;
            return false;
        }

        auto oldXArray = table->GetColumn(0);
        //旧的x列名称_theta
        auto oldXArrayName_theta = oldXArray->GetName();

        //存放原Y列的名称的数字部分。如"phi = 0"中 0.
        numVec.clear();
        //存放原Y列的名称的数字部分。如"phi = 0"中 phi.
        std::string oldY_base;
        //存放每次分割后的结果
        std::vector<std::string> tempRes;

        std::string m_separator = "=";

        //采用第一列("phi = 0")的基名称phi
        auto arrayName = table->GetColumn(1)->GetName();
        pst::CommonFunction::Stringsplit(arrayName, m_separator, tempRes);
        if (tempRes.size() != 2)
        {
            std::cout << "Stringsplit first 1 column error!" << std::endl;
            return false;
        }
        oldY_base = pst::CommonFunction::trim(tempRes[0]); //phi
        numVec.push_back(std::stod(pst::CommonFunction::trim(tempRes[1])));//0

        for (int i = 2; i < oldTableColumeNum; ++i)
        {
            //如phi = 0, phi = 1
            auto arrayName = table->GetColumn(i)->GetName();
            pst::CommonFunction::Stringsplit(arrayName, m_separator, tempRes);
            if (tempRes.size() != 2)
            {
                std::cout << "Stringsplit error! Column " << i << " name illegal! "
                    << " => " << arrayName << std::endl;
                return false;
            }
            numVec.push_back(std::stod(pst::CommonFunction::trim(tempRes[1])));
        }
        return true;
    }

    bool FarFieldDataGenerator::transformRCSTableToFourColumnsRectangularTable(
        vtkTable* inputTable, vtkTable* outputTable, double corlorOffset)
    {
        std::vector<double> phi_number;
        auto suc = ExtractPhiNum(inputTable, phi_number);
        if (!suc)
        {
            return false;
        }
        vtkNew<vtkDoubleArray> arrX_Theta;
        vtkNew<vtkDoubleArray> arrY_Phi;
        vtkNew<vtkDoubleArray> arrZ_R;
        vtkNew<vtkDoubleArray> arrColor;
        arrX_Theta->SetName("X");
        arrY_Phi->SetName("Y");
        arrZ_R->SetName("Z");
        arrColor->SetName("Color");

        double r = 0.;
        double theta = 0.;
        double phi = 0.;
        constexpr double my_pi = 3.141592653589793238462643383279502884;
        constexpr double val = my_pi / 180;

        auto oldXArray = inputTable->GetColumn(0);
        auto oldTableRowsNum = oldXArray->GetNumberOfTuples();

        m_originalTableRowNumber = oldTableRowsNum;
        m_originalTableColNumber = phi_number.size();
        m_tableExtends[0] = oldTableRowsNum - 1;
        m_tableExtends[1] = phi_number.size() - 1;

        double max = VTK_DOUBLE_MIN;
        double min = VTK_DOUBLE_MAX;
        for (int i = 0; i < oldTableRowsNum; ++i)
        {
            for (int j = 0; j < phi_number.size(); ++j)
            {
                r = inputTable->GetValue(i, j + 1).ToDouble();//第j个数实际对应原表的j+1列
                theta = oldXArray->GetVariantValue(i).ToDouble() * val;
                phi = phi_number[j] * val;
                //将球坐标转为直角坐标
                arrX_Theta->InsertNextValue(r * std::sin(theta) * std::cos(phi));
                arrY_Phi->InsertNextValue(r * std::sin(theta) * std::sin(phi));
                arrZ_R->InsertNextValue(r * std::cos(theta));
                arrColor->InsertNextValue(r + corlorOffset);
                if (r > max)
                {
                    max = r;
                }
                if (r < min)
                {
                    min = r;
                }
            }
        }
        //保证多次调用每次传出去的表不会增加重复内容
        vtkNew<vtkTable> tempTable;
        tempTable->AddColumn(arrX_Theta);
        tempTable->AddColumn(arrY_Phi);
        tempTable->AddColumn(arrZ_R);
        tempTable->AddColumn(arrColor);
        outputTable->DeepCopy(tempTable);

        return true;
    }

    void FarFieldDataGenerator::transformTableToStructuredGrid(
        vtkTable* inputTable, vtkStructuredGrid* outStructuredGrid, int xMax, int yMax, int zMax)
    {
        vtkNew<vtkTableToStructuredGrid> tableToSGFilter;
        tableToSGFilter->SetInputData(inputTable);
        tableToSGFilter->SetXColumn(inputTable->GetColumn(0)->GetName());
        tableToSGFilter->SetYColumn(inputTable->GetColumn(1)->GetName());
        tableToSGFilter->SetZColumn(inputTable->GetColumn(2)->GetName());
        tableToSGFilter->SetWholeExtent(0, xMax, 0, yMax, 0, zMax);

        tableToSGFilter->Update();

        //vtkNew< vtkStructuredGridWriter> writer;
        //writer->SetInputConnection(tableToSGFilter->GetOutputPort());
        //writer->SetFileName("FarField.vtk");
        //writer->Write();

        outStructuredGrid->DeepCopy(tableToSGFilter->GetOutput());
    }

    void FarFieldDataGenerator::logTheTable(vtkTable* inputTable,
        vtkTable* outputTable, double& logedMinimalValue)
    {
        auto rowsNum = inputTable->GetNumberOfRows();
        auto colsNum = inputTable->GetNumberOfColumns();

        outputTable->DeepCopy(inputTable);

        double minval = VTK_DOUBLE_MAX;
        //获取最小值
        for (int i = 1; i < colsNum; ++i)
        {
            for (int j = 0; j < rowsNum; ++j)
            {
                if (outputTable->GetValue(j, i).ToDouble() < minval)
                {
                    minval = outputTable->GetValue(j, i).ToDouble();
                }
            }
        }

        //第一列为Theta
        //平移，使最小值为0，保证r具有物理意义，为到球坐标系原点的距离
        const double fac = 0.00000001;

        if (std::abs(minval) < fac)//存在0
        {
            for (int i = 1; i < colsNum; ++i)
            {
                for (int j = 0; j < rowsNum; ++j)
                {
                    outputTable->SetValue(j, i,
                        m_logFactory * std::log10(outputTable->GetValue(j, i).ToDouble() + fac) - m_logFactory * std::log10(minval + fac));
                }
            }
            logedMinimalValue = m_logFactory * std::log10(minval + fac);
        }
        else
        {
            for (int i = 1; i < colsNum; ++i)
            {
                for (int j = 0; j < rowsNum; ++j)
                {
                    outputTable->SetValue(j, i,
                        m_logFactory * std::log10(outputTable->GetValue(j, i).ToDouble()) - m_logFactory * std::log10(minval));
                }
            }
            logedMinimalValue = m_logFactory * std::log10(minval);
        }
    }

    void FarFieldDataGenerator::normalizeTheTable(vtkTable* inputTable, vtkTable* outputTable)
    {
        auto rowsNum = inputTable->GetNumberOfRows();
        auto colsNum = inputTable->GetNumberOfColumns();

        outputTable->DeepCopy(inputTable);

        double maxVal = VTK_DOUBLE_MIN;
        //获取最大值
        for (int i = 1; i < colsNum; ++i)
        {
            for (int j = 0; j < rowsNum; ++j)
            {
                if (outputTable->GetValue(j, i).ToDouble() > maxVal)
                {
                    maxVal = outputTable->GetValue(j, i).ToDouble();
                }
            }
        }

        for (int i = 1; i < colsNum; ++i)
        {
            for (int j = 0; j < rowsNum; ++j)
            {
                auto value = outputTable->GetValue(j, i).ToDouble();
                outputTable->SetValue(j, i, value / maxVal);
            }
        }
    }

}
